package com.ebeijia.service.pay.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.ebeijia.common.CommonCodeDefine;
import com.ebeijia.common.CommonConstant;
import com.ebeijia.dto.OrderInfoDto;
import com.ebeijia.exception.ServiceException;
import com.ebeijia.mybatis.mapper.CommonUserMapper;
import com.ebeijia.mybatis.mapper.HomeSourceInfoMapper;
import com.ebeijia.mybatis.mapper.OrderInfoMapper;
import com.ebeijia.mybatis.mapper.PayInfoMapper;
import com.ebeijia.mybatis.mapper.UserInfoMapper;
import com.ebeijia.mybatis.pojo.HomeSourceInfo;
import com.ebeijia.mybatis.pojo.OrderInfo;
import com.ebeijia.mybatis.pojo.PayInfo;
import com.ebeijia.mybatis.pojo.UserInfo;
import com.ebeijia.pay.PayRefuse;
import com.ebeijia.pay.PayResult;
import com.ebeijia.pay.PaymentSDK;
import com.ebeijia.service.pay.PayHandleService;
import com.ebeijia.service.wechat.ITemplateMessageService;
import com.ebeijia.util.DateUtil;
import com.ebeijia.util.LoggerUtil;
import com.ebeijia.util.PropertiesUtils;
import com.ebeijia.util.SignUtils;
import com.ebeijia.util.StringUtil;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public  class PayhandleServiceImpl implements PayHandleService {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private OrderInfoMapper orderInfoMapper;
	@Autowired
	private HomeSourceInfoMapper homeInfoMapper;
	@Autowired
	private UserInfoMapper userInfoMapper;

	@Autowired
	private CommonUserMapper commonUserMapper;
	@Autowired
	private PayInfoMapper payInfoMapper;
	@Autowired
	private ITemplateMessageService templateMessageService;

	@Transactional
	public OrderInfoDto addOrder(OrderInfoDto orderInfo)
			throws ServiceException {

		OrderInfo genOrderInfo = new OrderInfo();
		String orderNo = commonUserMapper.genOrderNo();
		BeanUtils.copyProperties(orderInfo, genOrderInfo);
		// 金额以分为单位存储，传入金额为元
		BigDecimal orderAmt = new BigDecimal(orderInfo.getOrderAmt()).multiply(new BigDecimal(100));
		genOrderInfo.setTotalAmt(orderAmt);
		genOrderInfo.setPayAmt(orderAmt);
		Date curDate = new Date();
		
		genOrderInfo.setCreateTime(curDate);
		genOrderInfo.setUpdateTime(curDate);
		genOrderInfo.setOrderTime(curDate);
		genOrderInfo.setOrderNo(orderNo);
		orderInfo.setOrderStatus(CommonCodeDefine.WAIT_PAY.getCode());
		
		orderInfo.setOrderNo(orderNo);
		orderInfo.setOrderTime(curDate);
		orderInfoMapper.insertSelective(genOrderInfo);
		orderInfo.setId(genOrderInfo.getId());
		orderInfo.setPayAmt(orderAmt);
		logger.info("生成订单结束");
		return orderInfo;
	}

	protected PayResult sentToPay(OrderInfoDto dto) throws ServiceException {
		try {
			// 订单预支付信息
			PayInfo payInfo = new PayInfo();
			payInfo.setOrderId(dto.getId());
			Date curDate = new Date();
			payInfo.setCreateTime(curDate);
			payInfo.setUpdateTime(curDate);
			payInfo.setPayStatus(CommonConstant.PayStatus.NotPay.getCode());// 待支付
			payInfoMapper.insertSelective(payInfo);
			dto.setOpenId("");
			PayResult payResult = PaymentSDK.payInfo(dto.getOpenId(), dto
					.getOrderNo(), dto.getProDesc(), "任丘水务充值", dto.getPayAmt()
					.toBigInteger().toString(), DateUtil.formatDate(dto.getOrderTime(), "yyyyMMddHHmmss"),
					"");
			if (CommonCodeDefine.ERROR_PAY_FAIL.equals(payResult.getStatus())) {
				payInfo.setPayStatus(CommonConstant.PayStatus.PayUnPay
						.getCode());
				payInfo.setUpdateTime(new Date());
				payInfoMapper.updateByPrimaryKeySelective(payInfo);
			}

			return payResult;
		} catch (Exception e) {
			throw new ServiceException(e);
		}
	}

	/**
	 * 生成订单并调用威富通申请支付
	 */
	@Transactional
	public OrderInfoDto toAuthPay(OrderInfoDto orderInfoDto)
			throws ServiceException {
		OrderInfoDto dto = this.addOrder(orderInfoDto);
		PayResult payReuslt = sentToPay(dto);
		dto.setTokenId(payReuslt.getTokenId());
		dto.setSentStatus(payReuslt.getStatus());
		return dto;
	}

	/**
	 * 支付结果通知处理
	 */
	@Transactional
	public String payResultHandle(Map<String, String> resultMap)
			throws ServiceException {
		// 默认失败
		String status;
		try {
			status = "1";
			if (resultMap.containsKey("sign")) {
				// 验证签名失败直接返回
				if (!SignUtils.checkParam(resultMap,
						PropertiesUtils.getProperties("mch_key"))) {
					LoggerUtil.info(" 验证签名失败");
					return status;
				}

				if (!"0".equals(resultMap.get("status"))) {
					return status;
				}

				String resultCode = resultMap.get("result_code");
				OrderInfo orderInfo = null;
				PayInfo payInfo = null;
				// 支付成功
				if ("0".equals(resultCode)) {
					String orderNo = resultMap.get("out_trade_no");
					Map<String, Object> paramMap = new HashMap<String, Object>();
					paramMap.put("orderNo", orderNo);
					orderInfo = orderInfoMapper.selectByParams(paramMap);
					if (orderInfo != null) {
						paramMap.put("orderId", orderInfo.getId());
						payInfo = payInfoMapper.selectByParams(paramMap);

						if (payInfo != null) {
							if (!CommonConstant.PayStatus.NotPay.getCode()
									.equals(payInfo.getPayStatus())) {
								logger.info("已收到通知 ");
								return "0";
							}
							payInfo.setTradeType(resultMap.get("trade_type"));
							payInfo.setPayResult(resultMap.get("pay_result"));
							payInfo.setPayInfo(resultMap.get("pay_info"));
							payInfo.setTransactionId(resultMap
									.get("transaction_id"));
							payInfo.setOutTransactionId(resultMap
									.get("out_transaction_id"));
							payInfo.setOutTradeNo(resultMap.get("out_trade_no"));
							String totalFee = resultMap.get("total_fee");
							String coupon = resultMap.get("coupon_fee");
							payInfo.setTotalFee(new BigDecimal(StringUtils
									.isEmpty(totalFee) ? "0" : totalFee));
							payInfo.setCouponFee(new BigDecimal(StringUtils
									.isEmpty(coupon) ? "0" : coupon));
							payInfo.setFeeType(resultMap.get("fee_type"));
							payInfo.setAttach(resultMap.get("attach"));
							payInfo.setBankType(resultMap.get("bank_type"));
							payInfo.setBankBillno(resultMap.get("bank_billno"));
							payInfo.setOldPayStatus(payInfo.getPayStatus());
							payInfo.setPayStatus(CommonConstant.PayStatus.PaySuccess
									.getCode());// 支付成功
							payInfo.setPayTime(resultMap.get("time_end"));
							payInfo.setTradeState("SUCCESS");
							payInfo.setUpdateTime(new Date());
							int upLen = payInfoMapper
									.updateByCondition(payInfo);
							if (upLen > 0) {
								// 通知水厂缴费入账
								noticeWaterPayment(payInfo, orderInfo);
							}

						}
					}

					// 支付失败无需任何处理
				} else {
					handlePayFail(payInfo, orderInfo);
				}

				// 标示接受回调处理成功
				status = "0";

			}
		} catch (Exception e) {
			throw new ServiceException(e.getMessage(), e);
		}
		return status;
	}

	/**
	 * 处理支付失败
	 * @param payInfo
	 * @param orderInfo
	 */
	protected   void  handlePayFail(PayInfo payInfo, OrderInfo orderInfo){
		OrderInfo orderUpdateInfo=new OrderInfo();
		orderUpdateInfo.setId(orderInfo.getId());
		orderUpdateInfo.setOrderStatus(CommonCodeDefine.PAY_FAIL.getCode());
		orderInfoMapper.updateByPrimaryKeySelective(orderUpdateInfo);
	}

	private void noticeWaterPayment(PayInfo payInfo, OrderInfo orderInfo)
			throws Exception {
		UserInfo userInfo = userInfoMapper.selectByPrimaryKey(orderInfo
				.getUserId());
		// 推送支付结果微信消息
		String url = "";
		StringBuffer remark = new StringBuffer();
		BigDecimal payFee = payInfo.getTotalFee();

		// 入账
		Map params = new HashMap();
		params.put("orderNo", orderInfo.getOrderNo());
		params.put("bankDate",
				DateUtil.formatDate(orderInfo.getOrderTime(), "yyyy-MM-dd"));
		params.put("rcvAmt", payFee.divide(new BigDecimal("100")));
		params.put("userNo", orderInfo.getUserNo());
		params.put("phoneNo", orderInfo.getUserPhone());
		params.put("userName", orderInfo.getUserName());
		commonUserMapper.noticeToRecharge(params);

		String result = String.valueOf(params.get("result"));
		OrderInfo orderUpdateInfo=new OrderInfo();
		orderUpdateInfo.setId(orderInfo.getId());
		//	调充值接口失败
		if ("0".equals(result)) {
			refund(payInfo, orderInfo);
			orderUpdateInfo.setOrderStatus(CommonCodeDefine.PAY_SUCCEE_REFUND.getCode());
			//成功
		}else{
			orderUpdateInfo.setOrderStatus(CommonCodeDefine.PAY_SUCCESS.getCode());
		}
		orderInfoMapper.updateByPrimaryKeySelective(orderUpdateInfo);

	}

	/**
	 * 充值失败，退款处理
	 * @param payInfo
	 * @param orderInfo
	 * @throws Exception
	 */
	private void refund(PayInfo payInfo, OrderInfo orderInfo) throws Exception {

		String outRefundNo = commonUserMapper.genOrderNo();
		UserInfo userInfo = userInfoMapper.selectByPrimaryKey(orderInfo
				.getUserId());
		// resultJson.total_fee.toString() //resultJson.total_fee.toString()
		String resRez = PaymentSDK.submitRefund(userInfo.getOpenId(), orderInfo
				.getOrderNo(), payInfo.getTransactionId(), outRefundNo, payInfo
				.getTotalFee().toString(), payInfo.getTotalFee().toString(),
				"ORIGINAL");

		ObjectMapper omRefu = new ObjectMapper();
		omRefu.setDateFormat(new SimpleDateFormat("yyyyMMddHH:mm:ss"));
		omRefu.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
				false);
		logger.info("退款接口返回数据：" + resRez);
		PayRefuse fuseJson = omRefu.readValue(resRez, PayRefuse.class);
		if ("0".equals(fuseJson.getResult_code())
				&& "0".equals(fuseJson.getStatus())) {// 退款成功
			// 更新订单处理失败，退单处理
			payInfo.setTransactionId(fuseJson.getTransaction_id());
			payInfo.setOutRefundNo(fuseJson.getOut_refund_no());// 退款单号
			payInfo.setRefundId(fuseJson.getRefund_id());// 支付返回的
			payInfo.setRefundChannel(fuseJson.getRefund_channel());// 退款渠道
			if (fuseJson.getRefund_fee() != null)
				payInfo.setRefundFee(new BigDecimal(fuseJson.getRefund_fee()));// 退款金额
			if (fuseJson.getCoupon_refund_fee() != null)
				payInfo.setCouponRefundFee(new BigDecimal(fuseJson
						.getCoupon_refund_fee()));// 现金券退款金额
			payInfo.setPayStatus(CommonConstant.PayStatus.RefundSuccess
					.getCode());
			payInfo.setRefundTime(DateUtil.formatDate(new Date(),
					"yyyyMMddHHmmss"));// 退款时间
			payInfo.setRefundStatus("SUCCES");
			
			OrderInfo orderUpdateInfo=new OrderInfo();
			orderUpdateInfo.setId(orderInfo.getId());
				orderUpdateInfo.setOrderStatus(CommonCodeDefine.PAY_SUCCESS.getCode());
			orderInfoMapper.updateByPrimaryKeySelective(orderUpdateInfo);

		} else {
			// 退款失败处理
			payInfo.setPayStatus(CommonConstant.PayStatus.RefundFail.getCode());// 退款失败
			payInfo.setRefundStatus("FAIL");
			payInfo.setRemark(fuseJson.getErr_msg());
		}
		// 更新支付结果数据
		payInfoMapper.updateByPrimaryKeySelective(payInfo);
		

	}
}
